﻿using Newtonsoft.Json.Linq;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Net.Mail;
using System.Net.Mime;
using System.Security.Cryptography;
using System.Threading;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using OpenCvSharp;
using System.IO;
using static System.Runtime.CompilerServices.RuntimeHelpers;
using System.ComponentModel;
using OpenCvSharp.Internal.Vectors;

namespace VIA.Integration.LeadShine
{
    public enum StopMode
    {
        /// <summary>
        /// 立即停止
        /// </summary>
        [Description("立即停止")]
        EmergencyStop = 0,
        /// <summary>
        /// 减速停止
        /// </summary>
        [Description("减速停止")]
        DecelerateStop = 1
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="IsEnabled">使能状态</param>
    /// <param name="CounterMode">计数器选择 0:指令位置计数器 1:编码器计数器</param>
    /// <param name="LimitMode">限位停止方式  0:立即停止 1:减速停止</param>
    /// <param name="NegativeLimit">负限位</param>
    /// <param name="PostiveLimit">正限位</param>
    public record SoftLimitValue(bool IsEnabled, ushort CounterMode, ushort LimitMode, double NegativeLimit, double PostiveLimit);

    public class DMCController : Automatic, ISwitchController, ISuportInitialization, IDisposable
    {
        private bool _disposed;
        private bool _isInitialized;
        private double speedPersent = 1;

        public ushort CardNo { get; }
        public double SpeedPersent
        {
            get => speedPersent;
            set
            {
                if (value <= 0 || value > 1)
                    throw new ArgumentOutOfRangeException("速度比率必须在0-1之间");
                speedPersent = value;
            }
        }

        public static Dictionary<int, string> AxisNames { get; } = new();
        public DMCController(ushort cardNo)
        {
            CardNo = cardNo;
        }

        //public static bool Read(CardIoPoint ioPoint)
        //{

        //    //if (ioPoint.IoMode == IoModes.Senser)
        //    //{
        //    //    var value = LTDMC.dmc_read_inbit((ushort)ioPoint.BoardNo, (ushort)ioPoint.PortNo);

        //    //    var va = LTDMC.dmc_read_inbit_ex((ushort)ioPoint.BoardNo, (ushort)ioPoint.PortNo, ref state);
        //    //    return value == 0;
        //    //}
        //    //else
        //    //    data = LTDMC.dmc_read_outbit((ushort)ioPoint.BoardNo, (ushort)ioPoint.PortNo);
        //    //return data == 0;
        //}

        public static bool Write(CardIoPoint ioPoint, bool value)
        {
            short data = LTDMC.dmc_write_outbit((ushort)ioPoint.BoardNo, (ushort)ioPoint.PortNo, value ? (ushort)0 : (ushort)1);
            return data == 0;
        }

        public bool Read(IoPoint point)
        {
            if (!_isInitialized) return false;
            if (point is CardIoPoint ioPoint)
            {
                short data = short.MinValue;
                ushort state = 0;
                short ret = ioPoint.IoMode == IoModes.Senser ? LTDMC.dmc_read_inbit_ex((ushort)ioPoint.BoardNo, (ushort)ioPoint.PortNo, ref state) : LTDMC.dmc_read_outbit_ex((ushort)ioPoint.BoardNo, (ushort)ioPoint.PortNo, ref state);
                if (ret == 0)
                    return state == 0;
                else
                    throw new LeadShineException($"IO读取失败[BoardNo:{ioPoint.BoardNo},Port:{ioPoint.PortNo}]", ret);
            }
            else throw (new Exception($"IoPoint类型无地址参数，无法读取！"));
        }

        public void Write(IoPoint point, bool value)
        {
            if (!_isInitialized) return;
            if (point is CardIoPoint ioPoint)
            {
                short ret = LTDMC.dmc_write_outbit((ushort)ioPoint.BoardNo, (ushort)ioPoint.PortNo, value ? (ushort)0 : (ushort)1);
                if (ret != 0)
                {
                    throw new LeadShineException($"IO写入失败[BoardNo:{ioPoint.BoardNo},Port:{ioPoint.PortNo}]", ret);
                }
            }
            else throw (new Exception($"IoPoint类型无地址参数，无法写入！"));
        }
        ///// <summary>
        ///// 初始化板卡
        ///// </summary>
        ///// <param name="error"></param>
        ///// <returns></returns>
        //public void InitCard()
        //{
        //    short ret = LTDMC.dmc_board_init();//获取卡数量
        //    if (ret <= 0 || ret > 8)
        //    {
        //        throw new LeadShineException("初始卡失败，未检测到IO卡！", ret);
        //    }
        //    else
        //    {
        //        ushort usNum = 0;
        //        ushort[] arrusCardList = new ushort[8];
        //        uint[] arrunCardTypes = new uint[8];
        //        ret = LTDMC.dmc_get_CardInfList(ref usNum, arrunCardTypes, arrusCardList);
        //        if (ret != 0)
        //        {
        //            throw new LeadShineException("获取卡信息失败", ret);
        //        }
        //        ushort usCardId = arrusCardList[0];
        //    }
        //}

        public async Task InitializeAsync()
        {
            if (_isInitialized) return;
            var ret = LTDMC.dmc_board_init();
            if (ret <= 0)
                throw new LeadShineException("没有找到控制卡", ret);
            //var ret = LTDMC.dmc_board_init_onecard(CardNo);
            //if (ret < 0)
            //    throw new LeadShineException($"有2张或2张以上控制卡的硬件设置卡号相同[{Math.Abs(ret) - 1}]", ret);
            _isInitialized = true;
            await Task.FromResult(true);
        }
        public void SetAxisVelocity(ushort axisNo, VelocityCurve velocityCurveParams)
        {
            if (velocityCurveParams.Tacc <= 0)
                velocityCurveParams.Tacc = 0.1;
            if (velocityCurveParams.Tdec <= 0)
                velocityCurveParams.Tdec = 0.1;

            var ret = LTDMC.dmc_set_profile_unit(CardNo, axisNo, velocityCurveParams.Strvel, velocityCurveParams.Maxvel * SpeedPersent, velocityCurveParams.Tacc, velocityCurveParams.Tdec, velocityCurveParams.Endvel);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]设置轴速度参数失败", ret);
        }
        public VelocityCurve GetAxisVelocity(ushort axisNo)
        {
            double minVel = 0, maxVel = 0, tacc = 0, tdec = 0, stopVel = 0;
            var ret = LTDMC.dmc_get_profile_unit(CardNo, axisNo, ref minVel, ref maxVel, ref tacc, ref tdec, ref stopVel);
            ThrowIfError($"获取轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]设置轴速度参数失败", ret);
            return new VelocityCurve { Strvel = minVel, Maxvel = maxVel, Tacc = tacc, Tdec = tdec, Endvel = stopVel };
        }
        public void AbsoluteMove(ushort axisNo, double position, VelocityCurve velocityCurveParams)
        {
            if (velocityCurveParams != null)
                SetAxisVelocity(axisNo, velocityCurveParams);
            var ret = LTDMC.dmc_pmove_unit(CardNo, axisNo, position, 1);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]绝对移动失败", ret);
        }
        public void RelativeMove(ushort axisNo, double position, VelocityCurve velocityCurveParams)
        {
            if (velocityCurveParams != null)
                SetAxisVelocity(axisNo, velocityCurveParams);
            var ret = LTDMC.dmc_pmove_unit(CardNo, axisNo, position, 0);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]绝对移动失败", ret);
        }
        /// <summary>
        /// 判断指定坐标系是否在使用中
        /// </summary>
        /// <param name="coordNo"></param>
        /// <returns></returns>
        public bool IsDone(ushort coordNo)
        {
            return LTDMC.dmc_check_done_multicoor(CardNo, coordNo) == 1;
        }
        /// <summary>
        /// 线性插补 绝对坐标移动
        /// </summary>
        /// <param name="coordNo"></param>
        /// <param name="axies"></param>
        /// <param name="positions"></param>
        /// <param name="velocityCurve"></param>
        public void AbsoluteMove(ushort coordNo, ushort[] axies, double[] positions, VelocityCurve velocityCurve)
        {
            if (velocityCurve != null)
            {
                if (velocityCurve.Tacc <= 0)
                    velocityCurve.Tacc = 0.1;
                if (velocityCurve.Tdec <= 0)
                    velocityCurve.Tdec = 0.1;
                LTDMC.dmc_set_vector_profile_unit(CardNo, coordNo, velocityCurve.Strvel, velocityCurve.Maxvel, velocityCurve.Tacc, velocityCurve.Tdec, velocityCurve.Endvel);
            }
            var ret = LTDMC.dmc_line_unit(CardNo, coordNo, (ushort)axies.Length, axies, positions, 1);
            if (ret != 0)
                throw new LeadShineException($"轴[{string.Join(",", axies.Select(x => x.ToString()))}]绝对移动失败", ret);
        }

        /// <summary>
        /// 线性插补
        /// </summary>
        /// <param name="coordNo"></param>
        /// <param name="axies"></param>
        /// <param name="positions"></param>
        /// <param name="velocityCurve"></param>
        public void RelativeMove(ushort coordNo, ushort[] axies, double[] positions, VelocityCurve velocityCurve)
        {
            if (velocityCurve != null)
            {
                if (velocityCurve.Tacc <= 0)
                    velocityCurve.Tacc = 0.1;
                if (velocityCurve.Tdec <= 0)
                    velocityCurve.Tdec = 0.1;
                LTDMC.dmc_set_vector_profile_unit(CardNo, coordNo, velocityCurve.Strvel, velocityCurve.Maxvel, velocityCurve.Tacc, velocityCurve.Tdec, velocityCurve.Endvel);
            }
            var ret = LTDMC.dmc_line_unit(CardNo, coordNo, (ushort)axies.Length, axies, positions, 0);
            if (ret != 0)
                throw new LeadShineException($"轴[{string.Join(",", axies.Select(x => x.ToString()))}]相对移动失败", ret);
        }
        /// <summary>
        ///     连续运动
        /// </summary>
        /// <param name="axisNo"></param>
        /// <param name="moveDirection"></param>
        /// <param name="velocityCurveParams"></param>
        /// <returns></returns>
        public void ContinuousMove(ushort axisNo, MoveDirection moveDirection, VelocityCurve velocityCurveParams)
        {
            if (velocityCurveParams != null)
            {
                if (velocityCurveParams.Tacc <= 0)
                    velocityCurveParams.Tacc = 0.1;
                if (velocityCurveParams.Tdec <= 0)
                    velocityCurveParams.Tdec = 0.1;
                SetAxisVelocity(axisNo, velocityCurveParams);
            }
            var ret = LTDMC.dmc_vmove(CardNo, axisNo, (ushort)moveDirection);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}]{moveDirection.GetDescription()}移动失败", ret);
        }
        ///// <summary>
        ///// 获取轴参数
        ///// </summary>
        ///// <returns></returns>
        //public short GetParam()
        //{
        //    double startVel = 1, maxVel = 1, accTime = 0.1, decTime = 0.1, stopVel = 0, sparaTime = 0, pulseEquivalent = 1;
        //    ReturnState = LTDMC.dmc_get_profile_unit(CardId, NoId, ref startVel, ref maxVel, ref accTime, ref decTime, ref stopVel);
        //    ReturnState = LTDMC.dmc_get_s_profile(CardId, NoId, 0, ref sparaTime);
        //    ReturnState = LTDMC.dmc_get_equiv(CardId, NoId, ref pulseEquivalent);
        //    Option.StartVel = startVel;
        //    Option.MaxVel = maxVel;
        //    Option.AccTime = accTime;
        //    Option.DecTime = decTime;
        //    Option.StopVel = stopVel;
        //    Option.SparaTime = sparaTime;
        //    Option.PulseEquivalent = pulseEquivalent;

        //    double nLimit = 0, pLimit = 0;
        //    ushort enable = 0, source_sel = 0, SL_action = 0;
        //    ReturnState = GetSoftLimit(ref nLimit, ref pLimit, ref enable, ref source_sel, ref SL_action);
        //    Option.NagetiveLimit = nLimit;
        //    Option.PositiveLimit = pLimit;

        //    ushort homeMode = 0;
        //    double homeHighSpeed = 0, homeLowSpeed = 0, homeTacc = 0, homeDecc = 0, offsetSteps = 0;
        //    ReturnState = LTDMC.nmc_get_home_profile(CardId, NoId, ref homeMode, ref homeLowSpeed, ref homeHighSpeed, ref homeTacc, ref homeDecc, ref offsetSteps);
        //    Option.HomeAccTime = homeTacc;
        //    Option.HomeDecTime = homeDecc;
        //    Option.HomeLowSpeed = homeLowSpeed;
        //    Option.HomeHighSpeed = homeHighSpeed;
        //    Option.HomeMode = homeMode;
        //    Option.HomeOffset = offsetSteps;
        //    return ReturnState;
        //}

        /// <summary>
        ///     获取轴当前位置
        /// </summary>
        /// <param name="axisNo">轴标识</param>
        /// <returns>当前位置</returns>
        public double GetCurrentPosition(ushort axisNo)
        {
            double position = 0;
            var ret = LTDMC.dmc_get_position_unit(CardNo, axisNo, ref position);
            return position;
        }

        public double GetPulseEquivalent(ushort axisNo)
        {
            double pulseEquivalent = 0;
            var ret = LTDMC.dmc_get_equiv(CardNo, axisNo, ref pulseEquivalent);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]获取脉冲当量失败", ret);
            return pulseEquivalent;
        }
        public void SetPulseEquivalent(ushort axisNo, double pulseEquivalent)
        {
            var ret = LTDMC.dmc_set_equiv(CardNo, axisNo, pulseEquivalent);//设置脉冲当量
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]设置脉冲当量失败", ret);
        }
        /// <summary>
        /// 设置一维高速队列比较器
        /// </summary>
        /// <param name="channel">比较器号 也就是触发的通道，取值范围0-5（对应硬件 OUT2~OUT7 端口）</param>
        /// <param name="comparePostions">比较点，单位mm</param>
        /// <param name="level">有效电平，0-低电平，1-高电平</param>
        /// <param name="pulseWidth">输出脉冲宽度，单位：us，取值范围：1us~20s</param>
        public void SetupTriggerTable(ushort channel, IEnumerable<double> comparePostions, ElectricalLevel level = ElectricalLevel.Low, int pulseWidth = 1000)
        {
            LTDMC.dmc_hcmp_set_config(CardNo, channel, 1, 1, (ushort)level, pulseWidth);//配置比较器0关联轴axisId，比较源为辅助编码器计数器
            LTDMC.dmc_hcmp_clear_points(CardNo, channel);//清除比较点
            LTDMC.dmc_hcmp_set_mode(CardNo, channel, 4);//设置高速比较模式为队列模式

            foreach (var item in comparePostions)
            {
                LTDMC.dmc_hcmp_add_point_unit(CardNo, channel, item);
            }
        }

        /// <summary>
        /// 获取辅助编码器计数值
        /// </summary>
        /// <returns></returns>
        public int GetExtraEncoder()
        {
            int value = 0;
            LTDMC.dmc_get_extra_encoder(CardNo, 1, ref value);
            return value;
        }

        /// <summary>
        /// 设置辅助编码器计数值
        /// </summary>
        /// <param name="pos"></param>
        public void SetExtraEncoder(int pos)
        {
            LTDMC.dmc_set_extra_encoder(CardNo, 1, pos);
        }

        /// <summary>
        /// 清除触发表
        /// </summary>
        /// <param name="channel"></param>
        public void ClearTriggerTable(ushort channel)
        {
            ushort axis = 0; ushort cmp_source = 0; ushort cmp_logic = 0; int time = 0;
            LTDMC.dmc_hcmp_get_config(CardNo, (ushort)5, ref axis, ref cmp_source, ref cmp_logic, ref time);
            LTDMC.dmc_hcmp_clear_points(CardNo, channel);
            LTDMC.dmc_hcmp_set_mode(CardNo, channel, 0);
        }
        /// <summary>
        /// 设置轴的参数
        /// </summary>
        public void SetHomeParam(ushort axisNo, VelocityCurve velocityCurve, double homeOffset)
        {
            ushort homeMode = 0;
            double lowVel = 0, highVel = 0, tacc = 0, tdec = 0, offsetPos = 0;
            var ret = LTDMC.nmc_get_home_profile(CardNo, axisNo, ref homeMode, ref lowVel, ref highVel, ref tacc, ref tdec, ref offsetPos);
            ThrowIfError("获取回原参数失败", ret);
            ret = LTDMC.nmc_set_home_profile(CardNo, axisNo, homeMode, velocityCurve.Strvel, velocityCurve.Maxvel, velocityCurve.Tacc, velocityCurve.Tdec, homeOffset);

            ThrowIfError("设置回原参数失败", ret);
        }
        public (VelocityCurve VelocityCurve, double HomeOffset) GetHomeVelocityCurve(ushort axisNo)
        {
            ushort homeMode = 0;
            double lowVel = 0, highVel = 0, tacc = 0, tdec = 0, offsetPos = 0;
            var ret = LTDMC.nmc_get_home_profile(CardNo, axisNo, ref homeMode, ref lowVel, ref highVel, ref tacc, ref tdec, ref offsetPos);
            ThrowIfError("获取回原参数失败", ret);
            return (new VelocityCurve() { Strvel = lowVel, Maxvel = highVel, Tacc = tacc, Tdec = tdec }, offsetPos);
        }
        public AxisRunningMode GetRunningMode(ushort axisNo)
        {
            ushort mode = 0;
            var ret = LTDMC.dmc_get_axis_run_mode(CardNo, axisNo, ref mode);
            ThrowIfError("获取轴运动模式失败", ret);
            return (AxisRunningMode)mode;
        }
        public void ClearAlarm(ushort axisNo)
        {
            var ret = LTDMC.nmc_clear_axis_errcode(CardNo, axisNo);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]清除报警失败.", ret);
        }
        /// <summary>
        /// 检测轴是否运动完成，true：指定轴已运动完成，处于停止状态，false：指定轴未运动完成，处于运行状态
        /// </summary>
        /// <returns></returns>
        public bool CheckIsDone(ushort axisNo)
        {
            ushort state = 0;//0代表正在运行，1代表已停止
            var ret = LTDMC.dmc_check_done_ex(CardNo, axisNo, ref state);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]判断当前是否停止失败", ret);
            return state == 1;
        }
        /// <summary>
        ///     检查回零是否完成
        /// </summary>
        /// <param name="axisNo"></param>
        /// <returns></returns>
        public bool CheckHomeDone(ushort axisNo)
        {
            ushort state = 0;
            LTDMC.dmc_get_home_result(CardNo, axisNo, ref state);//判断回零是否正常完成。
            if (state != 1) return false;

            uint unIoState = LTDMC.dmc_axis_io_status(CardNo, axisNo);
            //bool b = (unIoState & 16) == 16;//检测原点信号是否亮
            LTDMC.dmc_set_position_unit(CardNo, axisNo, 0);//设置当前位置为原点?
            return true;

        }

        /// <summary>
        /// 检测状态
        /// </summary>
        /// <returns></returns>
        public DmcAxisState GetAxisState(ushort axisNo)
        {
            ushort state = 0;
            var ret = LTDMC.nmc_get_axis_state_machine(CardNo, axisNo, ref state);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]获取轴状态失败", ret);
            return (DmcAxisState)state;
        }
        public void Dispose()
        {
            LTDMC.dmc_board_close();
        }

        /// <summary>
        /// 紧急停止
        /// </summary>
        /// </summary>
        /// <param name="axisNo"></param>
        public void EmgStop(ushort axisNo)
        {
            var ret = LTDMC.dmc_stop(CardNo, axisNo, 1); //usStopMode:制动方式，0：减速停止，1：紧急停止
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]紧急停止失败", ret);
        }
        /// <summary>
        ///     读取指令位置计数器计数值
        /// </summary>
        /// <param name="axisNo"></param>
        /// <returns></returns>
        public double GetCommandPosition(ushort axisNo)
        {
            double pos = 0;
            var ret = LTDMC.dmc_get_position_unit(CardNo, axisNo, ref pos);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]读取指令计数器位置失败", ret);
            return pos;
        }

        /// <summary>
        ///     减速停止指定机构轴脉冲输出。
        /// </summary>
        /// <param name="axisNo"></param>
        public void DecelStop(ushort axisNo)
        {
            var ret = LTDMC.dmc_stop(CardNo, axisNo, 0); //usStopMode:制动方式，0：减速停止，1：紧急停止
            if (ret != 0 && _isInitialized)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]减速停止失败", ret);
        }
        [DebuggerStepThrough]
        void ThrowIfError(string message, short code)
        {
            if (code != 0 && _isInitialized)
                throw new LeadShineException(message, code);
        }
        /// <summary>
        /// 获取当前软限位值，根据脉冲当量换算为mm
        /// </summary>
        /// <param name="nLimit">返回负限位mm</param>
        /// <param name="pLimit">返回正限位mm</param>
        /// <param name="enable">返回使能状态0：禁止，1：允许</param>
        /// <param name="source_sel">返回计数器选择，0：指令位置计数器，1：编码器计数器</param>
        /// <param name="SL_action">返回限位停止方式，0：立即停止 1：减速停止</param>
        public SoftLimitValue GetSoftLimit(ushort axisNo)
        {
            double nLimit = 0d, pLimit = 0d;
            ushort enable = 0, source_sel = 0, SL_action = 0;
            var ret = LTDMC.dmc_get_softlimit_unit(CardNo, axisNo, ref enable, ref source_sel, ref SL_action, ref nLimit, ref pLimit);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]获取软限位参数失败", ret);
            return new SoftLimitValue(enable == 1, source_sel, SL_action, nLimit, pLimit);
        }
        /// <summary>
        /// 设置软限位位置，根据脉冲当量换算为mm
        /// </summary>
        /// <param name="nLimit">负限位mm</param>
        /// <param name="pLimit">正限位mm</param>
        /// <param name="source_sel">计数器选择，0：指令位置计数器，1：编码器计数器</param>
        /// <param name="SL_action">限位停止方式，0：立即停止 1：减速停止</param>
        public void SetSoftLimit(ushort axisNo, SoftLimitValue value)
        {
            var ret = LTDMC.dmc_set_softlimit_unit(CardNo, axisNo, (ushort)(value.IsEnabled ? 0 : 1), value.CounterMode, value.LimitMode, value.NegativeLimit, value.PostiveLimit);
        }
        public void MoveOrigin(ushort axisNo, VelocityCurve velocityCurve, double homeOffset)
        {
            if (velocityCurve != null)
                SetHomeParam(axisNo, velocityCurve, homeOffset);
            var ret = LTDMC.nmc_home_move(CardNo, axisNo);//启动回零 
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]回原点失败", ret);
        }
        /// <summary>
        /// 设置为原点，指令位置和编码器位置同时清0：不允许单独设置指令位置为0或者单独设置编码器位置为0
        /// </summary>
        public void SetOriginal(ushort axisNo, double position)
        {
            var ret = LTDMC.dmc_set_position_unit(CardNo, axisNo, position);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]设置原点失败", ret);
        }
        public double GetSpeed(ushort axisNo)
        {
            double sp = 0;
            var ret = LTDMC.dmc_read_current_speed_unit(CardNo, axisNo, ref sp);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]获取速度参数失败", ret);
            return sp;
        }
        /// <summary>
        /// 在线改变指定轴的当前运动速度
        /// </summary>
        /// <param name="speed">新的速度</param>
        /// <param name="reversal">是否反转方向</param>
        /// <returns></returns>
        public void ChangeSpeed(ushort axisNo, double speed, double taccdec = 0)
        {
            var ret = LTDMC.dmc_change_speed_unit(CardNo, axisNo, speed, taccdec);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]获取速度参数失败", ret);
        }
        public void ServoOn(ushort axisNo)
        {
            var ret = LTDMC.nmc_set_axis_enable(CardNo, axisNo);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]上使能失败", ret);
        }
        public void ServoOff(ushort axisNo)
        {
            var ret = LTDMC.nmc_set_axis_disable(CardNo, axisNo);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]上使能失败", ret);
        }
        /// <summary>
        /// 设置所有轴使能On
        /// </summary>
        /// <returns></returns>
        public void ServoOnAll()
        {
            var ret = LTDMC.nmc_set_axis_enable(CardNo, 255);
            ThrowIfError("设置所有轴使能On失败", ret);
        }

        /// <summary>
        /// 设置所有轴使能Off
        /// </summary>
        /// <param name="isEnable"></param>
        /// <returns></returns>
        public void ServoOffAll()
        {
            var ret = LTDMC.nmc_set_axis_disable(CardNo, 255);
            ThrowIfError("设置所有轴使能Off失败", ret);
        }
        /// <summary>
        /// 获取轴有关运动信号的状态,1-ON,0-OFF
        /// 0位:表示伺服报警信号 ALM
        /// 1位:表示正硬限位信号 +EL
        /// 2位:表示负硬限位信号–EL
        /// 3位:表示急停信号 EMG
        /// 4位:表示原点信号 ORG
        /// 5位:无
        /// 6位:表示正软限位信号+SL
        /// 7位:表示负软件限位信号-SL
        /// </summary>
        /// <returns></returns>
        public uint GetIOStatus(ushort axisNo)
        {
            //LTDMC.dmc_axis_io_status(CardNo, axisNo);
            uint state = 0;
            var ret = LTDMC.dmc_axis_io_status_ex(CardNo, axisNo, ref state);
            if (ret != 0)
                throw new LeadShineException($"轴[{AxisNames[axisNo]}-CH{(axisNo + 1)}]读取轴状态失败", ret);
            return state;
        }


        /// <summary>
        /// 紧急停止所有轴
        /// </summary>
        public void EmergencyStop()
        {
            var ret = LTDMC.dmc_emg_stop(CardNo);
            ThrowIfError("紧急停止所有轴失败", ret);
        }

        //public void StopAllAxis()
        //{
        //    var ret = LTDMC.dmc_stop(CardNo, 255, 0);
        //}

        /// <summary>
        /// 获取总线状态是否有异常，返回true代表有异常，false代表无异常
        /// </summary>
        /// <returns></returns>
        public bool CheckError()
        {
            ushort errcode = ushort.MinValue;
            var ret = LTDMC.nmc_get_errcode(CardNo, 2, ref errcode);
            ThrowIfError("获取总线状态是否异常失败", ret);
            return errcode == 0;
        }

        /// <summary>
        /// 清除总线错误状态
        /// </summary>
        public void ClearError()
        {
            var ret = LTDMC.nmc_clear_errcode(CardNo, 2);
            ThrowIfError("清除总线错误失败", ret);
        }

        /// <summary>
        /// 所有轴清除错误
        /// </summary>
        public void ClearAllAxisError()
        {
            var ret = LTDMC.nmc_clear_axis_errcode(CardNo, 1000);
            ThrowIfError("清除所有轴的异常", ret);
        }

        /// <summary>
        /// 下载参数文件,当使用相对路径时，参数文件与程序必须在同一目录下
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public void LoadConfig(string filePath)
        {
            if (!File.Exists(filePath))
                throw new ArgumentException("文件不存在");
            var ret = LTDMC.dmc_download_configfile(CardNo, filePath);
            ThrowIfError("下载参数文件失败", ret);
        }
        ///// <summary>
        ///// 总线卡硬件复位
        ///// </summary>
        ///// <returns></returns>
        //private async Task HardwareResetCard()
        //{
        //    LTDMC.dmc_board_reset();
        //    LTDMC.dmc_board_close();
        //    await Task.Delay(15_000);
        //    LTDMC.dmc_board_init();
        //}

        ///// <summary>
        ///// 总线卡软件复位
        ///// </summary>
        ///// <param name="sender"></param>
        ///// <param name="e"></param>
        ///// <returns></returns>
        //private async Task SoftwareResetCard(object sender, EventArgs e)
        //{
        //    LTDMC.dmc_soft_reset(CardNo);
        //    LTDMC.dmc_board_close();
        //    await Task.Delay(15_000);
        //    LTDMC.dmc_board_init();
        //}
        /// <summary>
        /// 获取轴停止原因
        /// </summary>
        /// <returns></returns>
        public int GetStopReason(ushort axisNo, out string reason)
        {
            int data = 0;
            var ret = LTDMC.dmc_get_stop_reason(CardNo, axisNo, ref data);
            reason = GetReasonDesc(data);
            return data;

            string GetReasonDesc(int data)
            {
                switch (data)
                {
                    case 0:
                        return "正常停止";
                    case 1:
                        return "ALM 立即停止";
                    case 2:
                        return "ALM 减速停止";
                    case 3:
                        return "LTC 外部触发立即停止";
                    case 4:
                        return "EMG 立即停止";
                    case 5:
                        return "正硬限位立即停止";
                    case 6:
                        return "负硬限位立即停止";
                    case 7:
                        return "正硬限位减速停止";
                    case 8:
                        return "负硬限位减速停止";
                    case 9:
                        return "正软限位立即停止";
                    case 10:
                        return "负软限位立即停止";
                    case 11:
                        return "正软限位减速停止";
                    case 12:
                        return "负软限位减速停止";
                    case 13:
                        return "命令立即停止";
                    case 14:
                        return "命令减速停止";
                    case 15:
                        return "其它轴引起的立即停止";
                    case 16:
                        return "其它轴引起的减速停止";
                    case 17:
                        return "模拟量超限，触发急停";
                    case 18:
                        return "保留";
                    case 19:
                        return "DSTP 信号引起的减速停止";
                    case 20:
                        return "前瞻预处理和速度规划来不及，底层自动调用 stoplist";
                    case 21:
                        return "原点不在两个限位之间停止";
                    case 22:
                        return "回零方向和当前有效限位端相反（正限位有效时，回零方向为负方向；负限位有效时，回零方向为正方向）";
                    case 23:
                        return "正负限位同时有效";
                    case 24:
                        return "没有找到 EZ 信号";
                    case 25:
                        return "回零位置溢出停止";
                    case 26:
                        return "动加速度过大，异常停止";
                    case 27:
                        return "双原点停止";
                    case 28:
                        return "区域限位立即停止";
                    case 29:
                        return "区域限位减速停止";
                    case 30:
                        return "龙门超差保护减速停止";
                    case 31:
                        return "龙门超差保护立即停止";
                    case 32:
                        return "插补规划错误停止";
                    case 33:
                        return "单轴跟踪误差保护立即停止";
                    case 34:
                        return "单轴跟踪误差保护减速停止";
                    case 35:
                        return "插补缓冲区错误停止";
                    case 36:
                        return "龙门主从轴超差保护立即停止";
                    case 37:
                        return "龙门主从轴超差保护减速停止";
                    case 38:
                        return "轴输出脉冲频率超过 4M";
                    case 39:
                        return "IO 触发立即停止";
                    case 40:
                        return "IO 触发减速停止";
                    case 49:
                        return "看门狗超时";
                    case 50:
                        return "两轴碰撞检测立即停止";
                    case 51:
                        return "两轴碰撞检测减速停止";
                    case 52:
                        return "龙门从轴 alm 引起主轴立即停止";
                    case 53:
                        return "从轴开始启动时主轴绝对位置错误（不在主轴运动方向上）";
                    case 54:
                        return "同步时主轴绝对位置错误（不在主轴运动方向上）";
                    case 55:
                        return "从轴开始运动位置大于同步时主轴绝对位置错误";
                    case 56:
                        return "同步时从轴绝对位置（不在从轴运动方向上）";
                    case 57:
                        return "不支持主轴运动模式（仅支持跟随主轴做定长和定速运动模式）";
                    case 58:
                        return "从轴追赶目标速度小于同步时从轴的速度";
                    case 59:
                        return "从轴同步位置过小，不足以从轴从当前速度直接加速或减速至同步速度";
                    case 60:
                        return "初始化时主轴运动方向错误(运动速度为零)";
                    case 61:
                        return "从轴开始运动时主轴未达到匀速状态";
                    case 62:
                        return "GearInPos 实际加速度大于设置的最大加速度";
                    case 63:
                        return "GearInPos 实际减速度大于设置的最大减速度";
                    case 64:
                        return "从轴追赶实际可达速度大于追赶设置的最大目标速度";
                    case 65:
                        return "从轴同步速度在只有加速或减速过程也不可达速度";
                    case 66:
                        return "二分法求取合适的可达速度，迭代次数超过限制次数让无法找到合适的速度值";
                    case 67:
                        return "主轴 pmove 目标位置小于主轴同步位置";
                    case 68:
                        return "主轴 pmove 目标位置小于从轴开始运动时的主轴位置";
                    case 69:
                        return "从轴追赶过程加速周期或减速周期为 0，有可能主轴同步位置和从轴开始运动时的主轴位置相隔太近";
                    case 70:
                        return "主轴目标速度为零";
                    case 71:
                        return "从轴实际可达速度大于追赶速度时，重算以追赶速度为目标速度的匀速周期数小于等于零";
                    case 72:
                        return "GearInPos 主轴位移与规划结果不一致";
                    case 73:
                        return "GearInPos 主轴 vmove 减速阶段不支持";
                    case 74:
                        return "从轴起始反向运动方向模式错误(1~4)";
                    case 75:
                        return "从轴起始反向运动加速度为零";
                    case 76:
                        return "连续轨迹等待外部 io 输入信号有效超时，停止插补系运动";
                    case 201:
                        return "正负限位之间全程没找到原点信号";
                    case 202:
                        return "回零方向不匹配";
                    case 203:
                        return "正负限位同时有效";
                    case 204:
                        return "正负限位之间全程没有 EZ 信号";
                    case 205:
                        return "位置溢出";
                    case 206:
                        return "双原点错误";
                    case 207:
                        return "外部信号触发回零停止";
                    case 208:
                        return "驱动器回零被中断停止";
                    default:
                        return "未知停止代码";
                }
            }
        }

        public short GetNodeOd(ushort CardNo, ushort PortNum, ushort nodenum, ushort index, ushort subindex, ushort valuelength, ref int value)
        {
            return LTDMC.nmc_get_node_od(CardNo, PortNum, nodenum, index, subindex, valuelength, ref value);
        }
        public short GetNodeOd(ushort CardNo, ushort PortNum, ushort nodenum, ushort index, ushort subindex, ushort valuelength, ref uint value)
        {
            return LTDMC.nmc_get_node_od(CardNo, PortNum, nodenum, index, subindex, valuelength, ref value);
        }
        public short GetNodeOd(ushort CardNo, ushort PortNum, ushort nodenum, ushort index, ushort subindex, ushort valuelength, ref short value)
        {
            return LTDMC.nmc_get_node_od(CardNo, PortNum, nodenum, index, subindex, valuelength, ref value);
        }

        public short SetNodeOd(ushort CardNo, ushort PortNum, ushort nodenum, ushort index, ushort subindex, ushort valuelength, int value)
        {
            return LTDMC.nmc_set_node_od(CardNo, PortNum, nodenum, index, subindex, valuelength, value);
        }

        public short SetOffsetPos(ushort CardNo, ushort axis, double offset_pos)
        {
            return LTDMC.nmc_set_offset_pos(CardNo, axis, offset_pos);
        }

        ///// <summary>
        ///// 设置一维高速线性比较器
        ///// </summary>
        ///// <param name="compareId">比较器号</param>
        ///// <param name="comparePostion">比较起始点，单位mm</param>
        ///// <param name="increment">设置高速比较线性模式参数，位置增量值</param>
        ///// <param name="count">设置高速比较线性模式参数，比较次数</param>
        ///// <param name="usCmpSource">1-比较源为辅助编码器位置</param>
        ///// <param name="usCmpLogic">有效电平，0-低电平，1-高电平</param>
        ///// <param name="nTime">输出脉冲宽度，单位：us，取值范围：1us~20s</param>
        //private void SetIncrementCompareConfig(ushort compareId, double comparePostion, double increment, int count, ushort usCmpSource = 1, ushort usCmpLogic = 1, int nTime = 1000)
        //{
        //    LTDMC.dmc_hcmp_set_config(CardId, compareId, NoId, usCmpSource, usCmpLogic, nTime);//配置比较源为辅助编码器计数器
        //    LTDMC.dmc_hcmp_clear_points(CardId, compareId);//清除比较点
        //    LTDMC.dmc_hcmp_set_mode(CardId, compareId, 5);//设置高速比较模式为线性模式
        //    LTDMC.dmc_hcmp_set_liner_unit(CardId, compareId, increment, count);//设置线性比较参数  
        //    LTDMC.dmc_hcmp_add_point_unit(CardId, compareId, comparePostion);//添加比较点位置
        //}

    }
}
